package fdupc.crypto;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * 类描述:  Des加密处理工具
 *
 * @author 王雷
 * @version 1.0.0
 * @date 2022/11/15 0015 上午 12:06
 */
@Slf4j
public class DesUtil {

    /**
     * 对给定的字符串以指定的编码方式和密钥进行加密
     *
     * @param srcStr  待加密的字符串
     * @param charset 字符集，如utf8
     * @param sKey    密钥
     * @return 处理结果
     */
    public static String encrypt(String srcStr, Charset charset, String sKey) {
        charset = (charset == null) ? StandardCharsets.UTF_8 : charset;
        return DesUtil.parseByte2HexStr(DesUtil.encrypt(srcStr.getBytes(charset), sKey));
    }

    /**
     * 对给定的字符串以指定的编码方式和密钥进行加密
     *
     * @param srcStr  待加密的字符串
     * @param sKey    密钥
     * @return 处理结果
     */
    public static String encrypt(String srcStr, String sKey) {
        return encrypt(srcStr, null, sKey);
    }

    /**
     * 对给定的密文以指定的编码方式和密钥进行解密
     *
     * @param hexStr  需要解密的密文
     * @param charset 字符集
     * @param sKey    密钥
     * @return 解密后的原文
     * @throws Exception 异常
     */
    public static String decrypt(String hexStr, Charset charset, String sKey) throws Exception {
        charset = (charset == null) ? StandardCharsets.UTF_8 : charset;
        return new String(DesUtil.decrypt(DesUtil.parseHexStr2Byte(hexStr), sKey), charset);
    }

    /**
     * 对给定的密文以指定的编码方式和密钥进行解密
     *
     * @param hexStr  需要解密的密文
     * @param sKey    密钥
     * @return 解密后的原文
     * @throws Exception 异常
     */
    public static String decrypt(String hexStr, String sKey) throws Exception {
        return decrypt(hexStr, null, sKey);
    }

    /**
     * 功能描述：加密逻辑处理
     *
     * @param data 需要加密的数据
     * @param sKey 加密的密钥
     * @return 加密结果
     * @date: 2022/11/15 0015 上午 12:32
     */
    public static byte[] encrypt(byte[] data, String sKey) {
        try {
            byte[] key = sKey.getBytes();

            IvParameterSpec iv = new IvParameterSpec(key);
            DESKeySpec desKey = new DESKeySpec(key);

            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(desKey);

            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");

            cipher.init(Cipher.ENCRYPT_MODE, securekey, iv);

            return cipher.doFinal(data);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     *
     * @param src  需要解密的数据
     * @param sKey 解密Key
     * @return 解密结果
     * @throws Exception 异常
     */
    public static byte[] decrypt(byte[] src, String sKey) throws Exception {
        byte[] key = sKey.getBytes();
        // 初始化向量
        IvParameterSpec iv = new IvParameterSpec(key);
        // 创建一个DESKeySpec对象
        DESKeySpec desKey = new DESKeySpec(key);
        // 创建一个密匙工厂
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        // 将DESKeySpec对象转换成SecretKey对象
        SecretKey securekey = keyFactory.generateSecret(desKey);
        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey, iv);
        // 真正开始解密操作
        return cipher.doFinal(src);
    }

    /**
     * 将二进制转换成16进制
     *
     * @param buf 需要转换的数据
     * @return 转换结果
     */
    public static String parseByte2HexStr(byte[] buf) {
        StringBuilder sb = new StringBuilder();
        for (byte b : buf) {
            String hex = Integer.toHexString(b & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr 需要转换的数据
     * @return 转换结果
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1) {
            return null;
        }
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    /*public static void main(String[] values) throws Exception {
        final String key = StringManagerUtil.randomNum(8);
        log.error("加密Key：{}", key);
        String data = encrypt("123456", key);
        log.error("加密后的结果：{}", data);
        log.error("解密后的结果：{}", decrypt(data, StandardCharsets.UTF_8, key));
    }*/
}
